home *** CD-ROM | disk | FTP | other *** search
- /* DoChecking.c
- * Functions that actually do the calls to the Word Services servers.
- * ©1992 Working Software, Inc.
- * This source code is copyrighted. Permission is granted to use the Word Services
- * portion of the Writeswell Jr. source code in your own programs, but you
- * may not distribute the Writeswell Jr. word-processor code as a
- * commercial product. If you modify the code, please do not call it
- * Writeswell Jr. (or Writeswell.) This will ensure that people understand the
- * program and don’t have to deal with a number of different versions with
- * who-knows-what going on in the code.
- *
- * Writeswell Jr. and Writeswell are trademarks of Working Software, Inc.
- * 28 Dec 91 Mike Crawford
- */
-
- #include <Aliases.h>
- #include <Processes.h>
- #include <AppleEvents.h>
- #include <AEObjects.h>
- #include <AEPackObject.h>
- #include <AERegistry.h>
- #include "TBConstants.h"
- #include "TBGlobals.h"
- #include "WordServices.h"
- #include "AppEvents.h"
- #include "ObWind.h"
- #include "ObText.h"
- #include "Gripe.h"
- #include "Prefs.h"
- #include "DoChecking.h"
- #include "FindProcess.h"
- #include "TableCheck.h"
-
- #define LAUNCH_BY_EVENT /* Undef this to use Proc Mgr instead of Finder AE */
-
- #define kLaunchTimeout 1800 /* If the speller's on a floppy, it may take a while */
- #define kBatchTimeout 600
-
- OSErr LaunchSpeller( AliasHandle aliasHdl );
-
- OSErr DoSpellCheck( short serviceNumber )
- {
- OSErr err;
- AEDesc docSpecifier;
- AEDesc textDescriptor;
- AEDesc textSpecifier;
- AEAddressDesc spellerAddr;
- AppleEvent btchEvent;
- AppleEvent replyEvent;
- WWJrPrefsHdl prefHdl;
- ServiceType servType;
-
- prefHdl = GetPrefHandle();
- if ( !prefHdl ){
- Gripe( "\pCannot get preferences handle" );
- return resNotFound;
- }
-
- err = OpenSpeller( serviceNumber, &spellerAddr, &servType );
- if ( err ){
- Gripe( "\pOpenSpeller failed to connect with speller" );
- return err;
- }
-
- switch ( servType ){
- case kBatchService:
- if ( (*prefHdl)->sendByList ){
- err = DoBatchCheck( &spellerAddr );
- if ( err ){
- Gripe( "\pDoBatchCheck failed" );
- return err;
- }
- }else{
- err = DoBatchTableCheck( &spellerAddr );
- if ( err ){
- Gripe( "\pDoBatchTableCheck failed" );
- return err;
- }
- }
- break;
- case kInteractiveService:
- Gripe( "\pInteractive service is not implemented yet" );
- return noErr;
- break;
- default:
- Gripe( "\pBad service type code in preferences file" );
- return noErr;
- }
-
- return noErr;
- }
-
- OSErr DoBatchCheck( AEAddressDesc *spellerAddrPtr )
- {
- OSErr err;
- AEDesc textSpecifier;
- AppleEvent btchEvent;
- AppleEvent replyEvent;
- WWJrPrefsHdl prefHdl;
- AEDescList textSpecList; /* 1.0d7 */
- long index; /* 1.0d7 */
-
- /* We make an object specifier that refers to _our_own_ window
- */
-
- err = CreateTextSpecifier( 1L, 1L, &textSpecifier );
-
- if ( err ){
- Gripe( "\pCreateTextSpecifier failed" );
- return err;
- }
-
- prefHdl = GetPrefHandle();
- if ( !prefHdl ){
- Gripe( "\pCannot get preferences handle" );
- return resNotFound;
- }
-
- if ( (*prefHdl)->checkSel ){
- /* Make a formRange descriptor that gives the selection range */
-
- Gripe( "\pSelection-only checking is not yet implemented" );
- return noErr;
- }
-
- /* Create the event to send to the speller */
-
- err = AECreateAppleEvent( kWordServicesClass,
- kWSBatchCheckMe,
- spellerAddrPtr,
- kAutoGenerateReturnID,
- kAnyTransactionID,
- &btchEvent );
-
- if ( err ){
- Gripe( "\pcreate btch event failed" );
- return err;
- }
- err = AEDisposeDesc( spellerAddrPtr );
- if ( err ){
- Gripe( "\pAEDisposeDesc failed" );
- return err;
- }
-
- #ifdef OLD_SPEC
-
- /* This was used until 1.0d6 */
-
- /* Insert the object specifier as the direct object of the batch event */
-
- err = AEPutParamDesc( &btchEvent,
- keyDirectObject,
- &textSpecifier );
- if ( err ){
- Gripe( "\pAEPutParamDesc failed to put direct object on batch event" );
- return err;
- }
- err = AEDisposeDesc( &textSpecifier );
- if ( err ){
- Gripe( "\pAEDisposeDesc failed" );
- return err;
- }
- #else
-
- /* 1.0d7 This is the new way to do it - use a list of object specifiers (even if
- * only one of them
- */
-
- err = AECreateList( (Ptr)NULL, (Size)0, false, &textSpecList );
- if ( err ){
- Gripe( "\pAECreateList failed" );
- return err;
- }
-
- /* Put our specifier into it. If we had multiple text blocks to check, we would
- * put specifiers for each into it in turn.
- * Note that we use AEPutDesc, not AEPutParamDesc, to put items into an indexed
- * list.
- */
-
- #define N_TEXT_SPECS 1L /*3L */ /* Define this to be 1 for normal checking */
-
- for ( index = 1L; index <= N_TEXT_SPECS; index++ ){
- err = AEPutDesc( &textSpecList,
- index,
- &textSpecifier );
- if ( err ){
- Gripe( "\pAEPutDesc failed to put text specifier into textSpecList" );
- return err;
- }
- }
-
- err = AEDisposeDesc( &textSpecifier );
- if ( err ){
- Gripe( "\pAEDisposeDesc failed" );
- return err;
- }
-
- /* Insert the list of object specifiers as the direct object of the batch event */
-
- err = AEPutParamDesc( &btchEvent,
- keyDirectObject,
- &textSpecList );
- if ( err ){
- Gripe( "\pAEPutParamDesc failed to put direct object on batch event" );
- return err;
- }
-
- /* 1.0.3 MDC fixed a bug in which we disposed of textSpecifier a second
- * time, instead of properly disposing of textSpecList
- */
-
- err = AEDisposeDesc( &textSpecList );
- if ( err ){
- Gripe( "\pAEDisposeDesc failed" );
- return err;
- }
- #endif
-
- /* Send the event. We await the reply, so that if there is a failure of some
- * sort in the initial connection, we can alert the user right away. The timeout
- * value to use here should be as long as one would care to have a user wait for
- * the completion of a menu command. Since we expect that the speller is on a local
- * machine in this case, and should be able to respond immediately, we just give
- * a few seconds for the timeout.
- *
- * We should assign an idle proc to spin the cursor. Even better would be a progress
- * dialog that says "Contacting speller" or some such, with an animated display that
- * shows the time elapsed relative to the total timeout, so the user will know how
- * long she may have to wait
- */
-
- err = AESend( &btchEvent,
- &replyEvent,
- kAEWaitReply + kAECanInteract + kAECanSwitchLayer,
- kAENormalPriority,
- kBatchTimeout,
- (AEIdleUPP)NULL,
- (AEFilterUPP)NULL );
-
- if ( err ){
- Gripe( "\psend batch event failed" );
- return err;
- }
- err = AEDisposeDesc( &btchEvent );
- if ( err ){
- Gripe( "\pAEDisposeDesc failed" );
- return err;
- }
-
- /* MDC 1.1.1 fix a memory leak */
-
- err = AEDisposeDesc( &replyEvent );
- if ( err ){
- Gripe( "\pAEDisposeDesc failed" );
- return err;
- }
-
- /* Now the event has been sent. There is nothing more that we have to actually do
- * on our own initiative to accomplish the spelling; we just sit back and respond
- * to events. In particular, we don't remember that spelling is taking place - once
- * the spelling is done, we will just start seeing events from the user (mouse and
- * key clicks and so on
- */
-
- return noErr;
- }
-
- OSErr OpenSpeller( short serviceNumber,
- AEAddressDesc *spellerAddrPtr,
- ServiceType *servTypePtr )
- {
- WWJrPrefsHdl prefHdl;
- short servID;
- AliasHandle aliasHdl;
- short curFile;
- OSType signature;
- ProcessSerialNumber psn;
- ProcessInfoRec pInfo;
- OSErr err;
-
- prefHdl = GetPrefHandle();
- if ( !prefHdl ){
- Gripe( "\pCannot get prefs handle" );
- return resNotFound;
- }
-
- servID = gServItemID[ serviceNumber - 1 ]; /* C arrays start at 0 */
-
- *servTypePtr = (*prefHdl)->serviceType[ servID - kServiceBaseID ];
-
- curFile = CurResFile();
- UseResFile( gPrefFileRefNum );
-
- aliasHdl = (AliasHandle)GetResource( rAliasType, servID );
-
- UseResFile( curFile );
-
- if ( !aliasHdl ){
- Gripe( "\pCannot get alias handle for service" );
- return resNotFound;
- }
-
- /* See if the speller is out there */
- signature = (*aliasHdl)->userType;
-
- if ( !FindAProcess( signature, &psn, &pInfo, (FSSpecPtr)NULL, (StringPtr)NULL ) ){
-
- EventRecord event;
- //short i;
-
- err = LaunchSpeller( aliasHdl );
- if ( err ){
- Gripe( "\pUnable to launch Word Services server" );
- return err;
- }
- #ifdef NEVER
- /* Got to sleep for a little while - otherwise the speller croaks */
- for ( i = 0; i < 10; i++ )
- WaitNextEvent( 0, &event, 1, (RgnHandle)NULL );
- #endif
- }
-
- err = AECreateDesc( typeApplSignature,
- (Ptr)&signature,
- sizeof( signature ),
- spellerAddrPtr );
- if ( err ){
- Gripe( "\pAECreateDesc failed" );
- return err;
- }
-
- return noErr;
- }
-
- #ifdef LAUNCH_BY_EVENT
- OSErr LaunchSpeller( AliasHandle aliasHdl )
- {
- OSErr err;
- FSSpec spellerSpec;
- Boolean changed;
- AppleEvent launchEvent;
- AppleEvent replyEvent;
- AEDesc aliasDesc;
- AEDesc folderDesc;
- FSSpec folderSpec;
- AEDesc finderAddr;
- DescType finderSig;
- AliasHandle fAliasHdl;
- AEDescList aliasList;
-
- /* Make sure the speller can still be found, and get its spec */
- err = ResolveAlias( (FSSpecPtr)NULL, aliasHdl, &spellerSpec, &changed );
-
- if ( err ){
- Gripe( "\pCannot locate speller" ); /* Might be user canceled AShare */
- return err;
- }
-
- if ( changed ){
- ChangedResource( (Handle) aliasHdl );
- WriteResource( (Handle) aliasHdl );
- }
-
- /* make an alias for the parent folder */
-
- err = FSMakeFSSpec( spellerSpec.vRefNum,
- spellerSpec.parID,
- (StringPtr)NULL,
- &folderSpec );
- if ( err ){
- Gripe( "\pMakeFSSpec failed" );
- return err;
- }
-
- err = NewAlias( (FSSpecPtr)NULL, &folderSpec, &fAliasHdl );
- if ( err ){
- Gripe( "\pNewAlias failed" );
- return err;
- }
-
- /* Create the event to send to the Finder */
-
- finderSig = 'MACS'; /* Creator code of finder; type is 'FNDR' */
- err = AECreateDesc( typeApplSignature,
- (Ptr)&finderSig,
- sizeof( finderSig ),
- &finderAddr );
- if ( err ){
- Gripe( "\pAECreateDesc failed" );
- return err;
- }
-
- err = AECreateAppleEvent( kAEFinderEvents,
- kAEOpenSelection,
- &finderAddr,
- kAutoGenerateReturnID,
- kAnyTransactionID,
- &launchEvent );
-
- if ( err ){
- Gripe( "\pcreate open selection event failed" );
- return err;
- }
- err = AEDisposeDesc( &finderAddr );
- if ( err ){
- Gripe( "\pAEDisposeDesc failed" );
- return err;
- }
-
- /* Insert the folder alias record as the direct object of the batch event */
-
- /* First make a descriptor of the alias */
- HLock( (Handle) fAliasHdl );
-
- err = AECreateDesc( typeAlias,
- (Ptr)*fAliasHdl,
- (*fAliasHdl)->aliasSize,
- &folderDesc );
-
- HUnlock( (Handle) fAliasHdl );
- DisposHandle( (Handle) fAliasHdl );
-
- if ( err ){
- Gripe( "\pAECreateDesc failed" );
- return err;
- }
-
- err = AEPutParamDesc( &launchEvent,
- keyDirectObject,
- &folderDesc );
- if ( err ){
- Gripe( "\pAEPutParamDesc failed to put direct object on open selection event" );
- return err;
- }
- err = AEDisposeDesc( &folderDesc );
- if ( err ){
- Gripe( "\pAEDisposeDesc failed" );
- return err;
- }
-
- /* Put the application alias on the event */
- HLock( (Handle) aliasHdl );
-
- err = AECreateDesc( typeAlias,
- (Ptr)*aliasHdl,
- (*aliasHdl)->aliasSize,
- &aliasDesc );
-
- HUnlock( (Handle) aliasHdl );
-
- if ( err ){
- Gripe( "\pAECreateDesc failed" );
- return err;
- }
-
- /* Now make a list of the alias descriptor. There is only one element in this
- * list
- */
-
- err = AECreateList( (Ptr)NULL, (Size)0, false, &aliasList );
-
- if ( err ){
- Gripe( "\pAECreateList failed" );
- return err;
- }
-
- err = AEPutDesc( &aliasList, 1L, &aliasDesc );
-
- if ( err ){
- Gripe( "\pAEPutDesc failed to put alias into alias list" );
- return err;
- }
-
- err = AEDisposeDesc( &aliasDesc );
- if ( err ){
- Gripe( "\pAEDisposeDesc failed" );
- return err;
- }
-
- err = AEPutParamDesc( &launchEvent,
- keySelection,
- &aliasList );
- if ( err ){
- Gripe( "\pAEPutParamDesc failed to put keySelection on open selection event" );
- return err;
- }
-
- err = AEDisposeDesc( &aliasList );
- if ( err ){
- Gripe( "\pAEDisposeDesc failed" );
- return err;
- }
-
- err = AESend( &launchEvent,
- &replyEvent,
- kAEWaitReply + kAECanInteract, /* Don't allow later switch */
- kAENormalPriority,
- kLaunchTimeout,
- (AEIdleUPP)NULL,
- (AEFilterUPP)NULL );
-
- if ( err ){
- Gripe( "\psend open selection event failed" );
- return err;
- }
- err = AEDisposeDesc( &launchEvent );
- if ( err ){
- Gripe( "\pAEDisposeDesc failed" );
- return err;
- }
-
- err = AEDisposeDesc( &replyEvent );
- if ( err ){
- Gripe( "\pAEDisposeDesc failed" );
- return err;
- }
-
- return noErr;
- }
- #else
-
- /* This makes the speller fail to process the batch event - I don't know why */
-
- OSErr LaunchSpeller( AliasHandle aliasHdl )
- {
- LaunchParamBlockRec pb;
- OSErr err;
- static FSSpec spellerSpec; // See Alan Rosenthal's note below
- Boolean changed;
- char *cPtr;
- short i;
-
- /*
- From: flaps@dgp.toronto.edu (Alan J Rosenthal)
- Subject: astonishing LaunchApplication fact!
- Organization: Dynamic Graphics Project, University of Toronto
- Date: 7 Jul 93 18:58:31 GMT
- Lines: 16
-
- I have discovered that the FSSpec pointed to by the launchAppSpec field in the
- parameter block for LaunchApplication is accessed AFTER LaunchApplication
- RETURNS. Thus you should not free it immediately afterwards, or if it is a
- local variable of a procedure, you must declare it as static so it persists if
- you're going to return from that procedure in the near future.
-
- This is what my problem last week with regards to launching applications with
- documents was really all about.
-
- It is consistent with my observations for it to be the case that this field is
- accessed only when the application is actually launched, which occurs when you
- do your next WaitNextEvent. In any case though, this pointer you pass in is
- being held on to for some amount of time.
-
- Alan "an Apple(tm) a day keeps your MacsBug away" Rosenthal
- */
-
- /* Make sure the speller can still be found */
- err = ResolveAlias( (FSSpecPtr)NULL, aliasHdl, &spellerSpec, &changed );
-
- if ( err ){
- Gripe( "\pCannot locate speller" ); /* Might be user canceled AShare */
- return err;
- }
-
- if ( changed ){
- ChangedResource( aliasHdl );
- WriteResource( aliasHdl );
- }
-
- cPtr = (char*)&pb;
-
- for ( i = 0; i < sizeof( pb ); i++ ){
- *cPtr++ = 0;
- }
-
- pb.launchBlockID = extendedBlock;
- pb.launchEPBLength = extendedBlockLen;
- pb.launchControlFlags = launchNoFileFlags + launchContinue /*+ launchDontSwitch*/;
- pb.launchAppSpec = &spellerSpec;
- pb.launchAppParameters = NULL;
-
- err = LaunchApplication( &pb );
-
- if ( err == memFullErr ){
-
- Gripe( "\pThere is not enough memory to launch the Word Services server" );
- return err;
- }
-
- if ( err ){
- Gripe( "\pUnable to launch the Word Services server" );
- return err;
- }
-
- return noErr;
- }
-
- #endif /* LAUNCH_BY_EVENT */